package com.xyy.saas.payment.adpater.yzh.util;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xyy.saas.payment.adpater.yzh.constant.ConfigPath;
import com.xyy.saas.payment.adpater.yzh.constant.DataDict;
import com.xyy.saas.payment.adpater.yzh.constant.XmlData;
import com.xyy.saas.payment.adpater.yzh.request.Request;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.util.ApolloUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * http请求工具类
 * @Author lala copy from yzh
 */
@Slf4j
public class HttpUtil {
    private static final int DEFAULT_CONNECTION_TIMEOUT = 1000 * 5; // 设置默认连接超时
    private static final int DEFAULT_SO_TIMEOUT = 1000 * 3; // 设置socket超时
    private static final String DEFAULT_CHARSET = "UTF-8"; // 设置默认通信入参编码为UTF-8
    /**
     * post 请求
     * @param request
     * @param url
     * @return
     * @throws Exception
     */
    public static Map<String, Object> post(Request request, String url) throws Exception {
        return postMethod(request, url);
    }

    @SneakyThrows
    public static Map<String, Object> getByUrl(String url) {
        HttpGet httpGet = new HttpGet(url);
        Map<String, Object> map = Maps.newHashMap();
        try (CloseableHttpClient httpClient = buildHttpClient(url)) {
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                map = parseResult(response, httpGet);
            }
        } catch (Exception e) {
            log.error("http get error. url:{}", url, e);
        }

        if (MapUtils.isEmpty(map)) {
            log.error("HttpUti.get result is empty");
            throw new PaymentException(ResultCodeEnum.DEFAULT_ERROR);
        }

        Integer status = (Integer) map.get(XmlData.STATUSCODE);
        if (status == null || status != HttpStatus.SC_OK) {
            log.error("HttpUti.get status is error, map:{}", JSON.toJSONString(map));
            throw new PaymentException(ResultCodeEnum.DEFAULT_ERROR);
        }
        return map;
    }

    /**
     * post请求
     *
     * @param request
     * @param url
     * @return
     * @throws Exception
     * @Description 发起HTTP-post请求
     */
    private static Map<String, Object> postMethod(Request request, String url) throws Exception {
        CloseableHttpClient httpClient = buildHttpClient(url);
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader(HTTP.CONTENT_TYPE, XmlData.CONTENT_TYPE_JSON);
        httpPost.setHeader(XmlData.DEALER_ID, ApolloUtil.getProperty(ConfigPath.HY_WX_PAY.equals(request.getMethod()) ?
                ConfigPath.WX_YZH_DEALERID : ConfigPath.YZH_DEALERID));
        httpPost.setHeader(XmlData.REQUEST_ID, UUID.randomUUID().toString().replace("-", ""));

        List<NameValuePair> params = Lists.newArrayList();
        params.add(new BasicNameValuePair(XmlData.MESS,  request.getMess()));
        params.add(new BasicNameValuePair(XmlData.TIMESTAMP, request.getTimestamp()+""));
        params.add(new BasicNameValuePair(XmlData.SIGN_TYPE, request.getSign_type()));
        params.add(new BasicNameValuePair(XmlData.DATA, request.getData()));
        params.add(new BasicNameValuePair(XmlData.SIGN, request.getSign()));

        CloseableHttpResponse response = null;
        Map<String, Object> map = Maps.newHashMap();
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
            response = httpClient.execute(httpPost);
            map = parseResult(response, httpPost);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return map;
    }

    /**
     * GET请求
     * @param request
     * @param url
     * @return
     * @throws Exception
     */
    public static Map<String, Object> get(Request request, String url, String method) throws Exception {
        return get(url + "?" + request.getPlainEncode(), method);
    }

    /**
     * get请求
     *
     * @param url
     * @return
     * @throws Exception
     * @Description 发起http-get请求
     */
    private static Map<String, Object> get(String url, String method) throws Exception {
        CloseableHttpClient httpClient = buildHttpClient(url);
        HttpGet httpget = new HttpGet(url);

        httpget.setHeader(HTTP.CONTENT_TYPE, XmlData.CONTENT_TYPE_JSON);
        httpget.setHeader(XmlData.DEALER_ID, ApolloUtil.getProperty(ConfigPath.HY_WX_PAY.equals(method) ?
                ConfigPath.WX_YZH_DEALERID : ConfigPath.YZH_DEALERID));
        httpget.setHeader(XmlData.REQUEST_ID, UUID.randomUUID().toString().replace("-", ""));

        CloseableHttpResponse response = null;
        Map<String, Object> map = Maps.newHashMap();
        try {
            // 执行get请求.
            response = httpClient.execute(httpget);
            map = parseResult(response, httpget);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return map;
    }

    private static CloseableHttpClient buildHttpClient(String url) throws Exception{
        if (StringUtils.isEmpty(url)) {
            throw new RuntimeException("HttpUtil error url:" + url);
        }
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(DataDict.CONNECTTIMEOUT)
                .setSocketTimeout(DataDict.SOCKETTIMEOUT)
                .build();
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build(),
                NoopHostnameVerifier.INSTANCE
        );
        return HttpClientBuilder.create()
                .setSSLSocketFactory(sslConnectionSocketFactory).setDefaultRequestConfig(config).build();
    }

    private static Map<String, Object> parseResult(CloseableHttpResponse response, HttpRequestBase http) throws Exception{
        Map<String, Object> resultMap = Maps.newHashMap();
        String result = null;
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != DataDict.STATUS_200) {
            if (statusCode == DataDict.STATUS_302) {
                result = response.getHeaders("location")[0].getValue();
            } else {
                http.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
        } else {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, XmlData.CHARSET);
            }
            Header[] headers = response.getAllHeaders();
            EntityUtils.consume(entity);
            resultMap.put(XmlData.HEADER, headers);
        }
        resultMap.put(XmlData.STATUSCODE, statusCode);
        resultMap.put(XmlData.DATA, result);
        return resultMap;
    }

    public static String post(String reqURL,String json) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(DEFAULT_SO_TIMEOUT).setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT).build();
        HttpPost hp = new HttpPost(reqURL);
        String respData = null;
        CloseableHttpResponse response = null;
        try {
            StringEntity s = new StringEntity(json,"UTF-8");
            s.setContentEncoding("UTF-8");
            s.setContentType("application/json");//发送json数据需要设置contentType
            hp.setEntity(s);
            hp.setHeader("Content-Type", "application/json");
            hp.setConfig(requestConfig);
            response = httpClient.execute(hp);
            HttpEntity resEntity = response.getEntity();
            if (null != resEntity) {
                respData = EntityUtils.toString(resEntity, DEFAULT_CHARSET);
            }
        } catch (Exception e) {
            throw new Exception(e);
        }finally {
            try {
                if(response!=null){
                    response.close();
                }
                if(httpClient!=null){
                    httpClient.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage(),e);
            }
        }
        return respData;
    }
}
